{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fc925562",
   "metadata": {},
   "source": [
    "# LangChain Expression Language (LCEL)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "044db1b7-c18c-45d2-be7a-29f027c901e2",
   "metadata": {
    "height": 115,
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import openai\n",
    "\n",
    "from dotenv import load_dotenv, find_dotenv\n",
    "_ = load_dotenv(find_dotenv()) # read local .env file\n",
    "openai.api_key = os.environ['OPENAI_API_KEY']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2de9d2bd-18de-44d5-81ac-5918e2106367",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "#!pip install pydantic==1.10.8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fd55c0a0-ca4e-4311-a33c-fcebeb7d8b1e",
   "metadata": {
    "height": 63
   },
   "outputs": [],
   "source": [
    "from langchain.prompts import ChatPromptTemplate\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.schema.output_parser import StrOutputParser"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e99c432b-b2c9-497b-9912-c9ca4c1e3740",
   "metadata": {},
   "source": [
    "## Simple Chain"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6a0be20d-0e00-478c-a844-017cad13af22",
   "metadata": {
    "height": 97
   },
   "outputs": [],
   "source": [
    "prompt = ChatPromptTemplate.from_template(\n",
    "    \"tell me a short joke about {topic}\"\n",
    ")\n",
    "model = ChatOpenAI()\n",
    "output_parser = StrOutputParser()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aedf1c1e-b697-47ce-9d81-eaec9192243b",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "chain = prompt | model | output_parser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6df32028-d35f-4392-bb15-ddeec9ee09b5",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "chain.invoke({\"topic\": \"bears\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d8ba33b5-2ae9-44d7-b023-18c903af571a",
   "metadata": {},
   "source": [
    "## More complex chain\n",
    "\n",
    "And Runnable Map to supply user-provided inputs to the prompt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d036bb8e-8ca7-4dbd-8103-f50a3c8c3af9",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "from langchain.embeddings import OpenAIEmbeddings\n",
    "from langchain.vectorstores import DocArrayInMemorySearch"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8955cff7-f1a2-4f94-ab5b-fcdda0859702",
   "metadata": {
    "height": 97
   },
   "outputs": [],
   "source": [
    "vectorstore = DocArrayInMemorySearch.from_texts(\n",
    "    [\"harrison worked at kensho\", \"bears like to eat honey\"],\n",
    "    embedding=OpenAIEmbeddings()\n",
    ")\n",
    "retriever = vectorstore.as_retriever()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2df87934-1697-405c-b460-5e9bfd16c792",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "retriever.get_relevant_documents(\"where did harrison work?\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "871cb26b-97b3-4f63-8bb3-523d3e6d117b",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "retriever.get_relevant_documents(\"what do bears like to eat\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "127a7fb6-5821-4934-ab56-9e3300516c05",
   "metadata": {
    "height": 131
   },
   "outputs": [],
   "source": [
    "template = \"\"\"Answer the question based only on the following context:\n",
    "{context}\n",
    "\n",
    "Question: {question}\n",
    "\"\"\"\n",
    "prompt = ChatPromptTemplate.from_template(template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ec01c56-731c-4e4f-a5f6-493fba953db0",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "from langchain.schema.runnable import RunnableMap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a9ca6506-826f-4420-8f19-25dd4dbbc1dc",
   "metadata": {
    "height": 97
   },
   "outputs": [],
   "source": [
    "chain = RunnableMap({\n",
    "    \"context\": lambda x: retriever.get_relevant_documents(x[\"question\"]),\n",
    "    \"question\": lambda x: x[\"question\"]\n",
    "}) | prompt | model | output_parser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "707d1319-8840-4ed5-b4a4-a2a128799db6",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "chain.invoke({\"question\": \"where did harrison work?\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05ec3727-4284-417e-9e23-eec0682eb002",
   "metadata": {
    "height": 97
   },
   "outputs": [],
   "source": [
    "inputs = RunnableMap({\n",
    "    \"context\": lambda x: retriever.get_relevant_documents(x[\"question\"]),\n",
    "    \"question\": lambda x: x[\"question\"]\n",
    "})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4216c7ab-6d1b-4f2a-98dc-5d2ace23e3c2",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "inputs.invoke({\"question\": \"where did harrison work?\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eec59c3b-33e7-437f-9b8b-b4652bc3b863",
   "metadata": {},
   "source": [
    "## Bind\n",
    "\n",
    "and OpenAI Functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f3efed3b-6d4c-42a4-9692-0cc4596f530b",
   "metadata": {
    "height": 301
   },
   "outputs": [],
   "source": [
    "functions = [\n",
    "    {\n",
    "      \"name\": \"weather_search\",\n",
    "      \"description\": \"Search for weather given an airport code\",\n",
    "      \"parameters\": {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\n",
    "          \"airport_code\": {\n",
    "            \"type\": \"string\",\n",
    "            \"description\": \"The airport code to get the weather for\"\n",
    "          },\n",
    "        },\n",
    "        \"required\": [\"airport_code\"]\n",
    "      }\n",
    "    }\n",
    "  ]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f8be4721-91d2-4ae6-8fdb-e91dc6ac1bc5",
   "metadata": {
    "height": 114
   },
   "outputs": [],
   "source": [
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"human\", \"{input}\")\n",
    "    ]\n",
    ")\n",
    "model = ChatOpenAI(temperature=0).bind(functions=functions)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e61b095d-9934-41b8-a794-a9dd57e9c733",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "runnable = prompt | model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a638efeb-b5ce-4aa4-8377-3e86597a03ab",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "runnable.invoke({\"input\": \"what is the weather in sf\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a22faf5-ea24-48d2-b028-03733b548225",
   "metadata": {
    "height": 539
   },
   "outputs": [],
   "source": [
    "functions = [\n",
    "    {\n",
    "      \"name\": \"weather_search\",\n",
    "      \"description\": \"Search for weather given an airport code\",\n",
    "      \"parameters\": {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\n",
    "          \"airport_code\": {\n",
    "            \"type\": \"string\",\n",
    "            \"description\": \"The airport code to get the weather for\"\n",
    "          },\n",
    "        },\n",
    "        \"required\": [\"airport_code\"]\n",
    "      }\n",
    "    },\n",
    "        {\n",
    "      \"name\": \"sports_search\",\n",
    "      \"description\": \"Search for news of recent sport events\",\n",
    "      \"parameters\": {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\n",
    "          \"team_name\": {\n",
    "            \"type\": \"string\",\n",
    "            \"description\": \"The sports team to search for\"\n",
    "          },\n",
    "        },\n",
    "        \"required\": [\"team_name\"]\n",
    "      }\n",
    "    }\n",
    "  ]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb43b030-459f-47e8-a27d-96c2d70cdfef",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "model = model.bind(functions=functions)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ff03e0d-d6c6-4b47-815e-d7ea5b248567",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "runnable = prompt | model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "03855fa3-5e2f-4ab2-aba0-c2cd5423239e",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "runnable.invoke({\"input\": \"how did the patriots do yesterday?\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bebc0c55-48c2-4105-90ec-7297553b8e6a",
   "metadata": {},
   "source": [
    "## Fallbacks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa0b1ea2-7aef-4449-a553-426cb8c5aa30",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "from langchain.llms import OpenAI\n",
    "import json"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bef73d77-9cac-419a-9583-8aefc6c9277b",
   "metadata": {},
   "source": [
    "**Note**: Due to the deprecation of OpenAI's model `text-davinci-001` on 4 January 2024, you'll be using OpenAI's recommended replacement model `gpt-3.5-turbo-instruct` instead."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "df432efe-9415-42e3-ab57-ecf4d439f369",
   "metadata": {
    "height": 114
   },
   "outputs": [],
   "source": [
    "simple_model = OpenAI(\n",
    "    temperature=0, \n",
    "    max_tokens=1000, \n",
    "    model=\"gpt-3.5-turbo-instruct\"\n",
    ")\n",
    "simple_chain = simple_model | json.loads"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "441928c5-8712-45c5-bfdf-6f51634198a7",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "challenge = \"write three poems in a json blob, where each poem is a json blob of a title, author, and first line\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0739e85f-8497-4471-8ec9-17e958d80771",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "simple_model.invoke(challenge)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a20d15c-dc8a-4b6d-a423-a5f814425219",
   "metadata": {},
   "source": [
    "**Note**: The next line is expected to fail."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2a5e8492-0927-4a3a-b939-947826246330",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "simple_chain.invoke(challenge)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6814143b-4a35-4d29-bd32-ba461274bcbf",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "model = ChatOpenAI(temperature=0)\n",
    "chain = model | StrOutputParser() | json.loads"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f55f04cf-0217-4106-b41f-0e0661d12c27",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "chain.invoke(challenge)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b5d3f035-b18d-4cba-854d-a43ef8554e48",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "final_chain = simple_chain.with_fallbacks([chain])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9a09fe6a-548c-412d-9468-9efe2b49f7c9",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "final_chain.invoke(challenge)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3fcfdda0-3db2-4073-a647-f2d62c460349",
   "metadata": {},
   "source": [
    "## Interface"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33b3b27f-b5a0-4db5-a1b0-20754437a47e",
   "metadata": {
    "height": 131
   },
   "outputs": [],
   "source": [
    "prompt = ChatPromptTemplate.from_template(\n",
    "    \"Tell me a short joke about {topic}\"\n",
    ")\n",
    "model = ChatOpenAI()\n",
    "output_parser = StrOutputParser()\n",
    "\n",
    "chain = prompt | model | output_parser"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48c8cabf-ea55-4448-b070-3ec22942c559",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "chain.invoke({\"topic\": \"bears\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cc58bdb4-a896-46ba-90c4-1b333245229a",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": [
    "chain.batch([{\"topic\": \"bears\"}, {\"topic\": \"frogs\"}])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a069d61-0a67-4368-b7c4-367262267bb8",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "for t in chain.stream({\"topic\": \"bears\"}):\n",
    "    print(t)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2315b43f-c7e1-4f7b-9595-4cabdc019dea",
   "metadata": {
    "height": 46
   },
   "outputs": [],
   "source": [
    "response = await chain.ainvoke({\"topic\": \"bears\"})\n",
    "response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f3082379-f75e-4a74-bee5-c18ddc5ac4dc",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "adccca48-787e-4219-af82-f18e6408182b",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5c816827-e5b7-480a-826b-0ca715faca3c",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "15e6d608-c205-4141-bab8-0304dd910978",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "abfc490d-090d-4e1c-b8ee-bf40ec4da4c3",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5fe48ff0-fd84-4c9e-8069-02117d57f7f0",
   "metadata": {
    "height": 29
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
